/*                                      _
 *     ___ _ __ ___ _ __ ___   ___   __| |
 *    / __| '__/ __| '_ ` _ \ / _ \ / _` |
 *    \__ \ |  \__ \ | | | | | (_) | (_| |
 *    |___/_|  |___/_| |_| |_|\___/ \__,_|                                  
 *
 *	   Versus Waterbrake for Survivors
 */

#define MODULE_NAME "WaterBrake"

#define FRAMESKIP 3 // Our OnGameFrame function will only trigger every third Frame
#define JUMPTIME 1.5 // How long the Plugin assumes you as 'jumping' after pressing JUMP
 
new bool:isInWater[MAXPLAYERS+1];
new bool:isJumping[MAXPLAYERS+1];
new bool:isJockeyed[MAXPLAYERS+1];
new bool:isAllowedMode;
new Handle:cvarJockeySlow = INVALID_HANDLE;

new enableBrake = 1;
new Float:slowSetting = 0.7;

new Handle:cvarEnabled = INVALID_HANDLE;
new Handle:cvarWaterSlow = INVALID_HANDLE;

new waterOffset;
new speedOffset;

new everyXFrame;


WaterBrake_OnPluginStart()
{
	_WB_HookEvents();

	cvarEnabled = CreateConVar("l4d2_srs_waterslow_enabled", "0", " Enable or Disable the Water Brake functionality ", SRS_CVAR_DEFAULT_FLAGS);
	cvarWaterSlow = CreateConVar("l4d2_srs_waterslow_setting", "0.7", " How much Survivors will be slowed down in Water, 0.7 means 70% speed ", SRS_CVAR_DEFAULT_FLAGS);
	cvarJockeySlow = CreateConVar("l4d2_srs_waterslow_jockey", "0", " Enable or Disable Water Brake for Jockeyed Survivors ", SRS_CVAR_DEFAULT_FLAGS);
	
	HookConVarChange(cvarEnabled, ConVarModule);
	HookConVarChange(cvarWaterSlow, ConVarModule);
	
	waterOffset = FindSendPropOffs("CTerrorPlayer", "m_nWaterLevel");
	speedOffset = FindSendPropInfo("CTerrorPlayer", "m_flLaggedMovementValue");
}

public ConVarModule(Handle:convar, const String:oldValue[], const String:newValue[])
{
	enableBrake = GetConVarBool(cvarEnabled);
	slowSetting = GetConVarFloat(cvarWaterSlow);
}

_WB_HookEvents()
{
	HookEvent("round_start", Waterbrake_RoundStart_Event);
	HookEvent("round_end", Waterbrake_RoundEnd_Event);
	HookEvent("jockey_ride", Waterbrake_PGrabbed_Event);
	HookEvent("jockey_ride_end", Waterbrake_PRelease_Event);
}

public Waterbrake_RoundStart_Event (Handle:event, const String:name[], bool:dontBroadcast)
{
	if (IsVersus()) isAllowedMode = true;
	else isAllowedMode = false;
	
	for (new target = 1; target <= MaxClients; target++)
	{
		isJockeyed[target] = false;
	}
}

public Waterbrake_RoundEnd_Event (Handle:event, const String:name[], bool:dontBroadcast)
{
	isAllowedMode = false;
}

Action:Waterbrake_OnPlayerRunCmd(client, &buttons)
{
	if (buttons & IN_JUMP && !isJumping[client])
	{
		isJumping[client] = true;
		CreateTimer(JUMPTIME, JumpDelay_Timer, client);
	}
}

public Action:JumpDelay_Timer(Handle:timer, any:client)
{
	isJumping[client] = false;
}

public Waterbrake_PGrabbed_Event(Handle:event, const String:name[], bool:dontBroadcast)
{
	if (!GetConVarBool(cvarJockeySlow)) return; // if its disabled, it wont ever set the antislowdown true

	new victimId = GetEventInt(event, "victim");
	if (!victimId || victimId > MAXPLAYERS) return;
	
	isJockeyed[victimId] = true;
}

public Waterbrake_PRelease_Event(Handle:event, const String:name[], bool:dontBroadcast)
{
	new victimId = GetEventInt(event, "victim");
	if (!victimId || victimId > MAXPLAYERS) return;
	
	isJockeyed[victimId] = false;
}

public OnGameFrame()
{
	if (!IsServerProcessing()) return;

	if (!isAllowedMode || !enableBrake) return;
	
	if (!survivorCount) return;
	
	everyXFrame++;
	if (everyXFrame >= FRAMESKIP)
	{
		everyXFrame = 1;
		
		for (new i = 1; i <= survivorCount; i++)
		{
			if (!IsValidEntity(survivorIndex[i]))
			{
				StateHelpers_RebuildSurvIndex();
				return;
			}
			
			new level = GetEntData(survivorIndex[i], waterOffset, 1);
			
			if (level > 0) // case Survivor in water
			{
				if (!isInWater[survivorIndex[i]] && !isJockeyed[i]) // isInWater will only be set true if no Jockey is involved
				{
					isInWater[survivorIndex[i]] = true;
					SetEntDataFloat(survivorIndex[i], speedOffset, 1.0 * slowSetting, true); // set bool and slowdown
				}
				else if (isInWater[survivorIndex[i]] && isJockeyed[i]) // case Jockey jumped on sometime after Survivor was in the water
				{
					isInWater[survivorIndex[i]] = false;
					SetEntDataFloat(survivorIndex[i], speedOffset, 1.0, true); // reset bool and speed
				}
			}
			else if (!isJumping[survivorIndex[i]]) // case Survivor not jumping, not in water
			{
				if (isInWater[survivorIndex[i]]) // case not in water anymore but slowed down by jumpdelay
				{
					isInWater[survivorIndex[i]] = false;
					SetEntDataFloat(survivorIndex[i], speedOffset, 1.0, true); // reset bool and speed
				}
			}
		}
	}
}

#undef MODULE_NAME